﻿namespace 战斗系统原型.战斗系统
{
    public class 启动战斗
    {
        public 启动战斗()
        {
            显示.输出行("开始战斗");

            主界面 界面 = new();
        }
    }

    internal class 主界面
    {
        int 窗口x大小, 窗口y大小;
        int 系统信息位置, 决意行位置, 击破行位置, 回合行位置, 主角状态起始行, 敌方状态起始行, 日志起始行, 操作菜单起始行;
        public static 主界面? 当前界面;
        private static object 单例锁 = new object();
        private List<string> 当前选项 = new();
        private int 当前选择项 = 0;
        public List<int> 已选项路径 = new();
        public List<int> 当前菜单路径 = new();
        public 主界面()
        {
            Console.Clear();
            lock (单例锁)
            {
                if (当前界面 != null)
                {
                    显示.日志输出(显示.日志类型.中断, "已拒绝创建多个数据实例...");
                    return;
                }
                当前界面 = this;
            }
            初始化定义();
            设定窗口大小(窗口x大小, 窗口y大小);
            启动界面刷新();
            获取按键();
        }
        private void 初始化定义()
        {
            窗口x大小 = 182;
            窗口y大小 = 43;
            系统信息位置 = 0;
            回合行位置 = 1;
            决意行位置 = 2;
            击破行位置 = 3;
            主角状态起始行 = 5;
            敌方状态起始行 = 主角状态起始行 + 5;
            日志起始行 = 敌方状态起始行 + 5;
            操作菜单起始行 = 日志起始行 + 11;

        }
        private void 设定窗口大小(int 横向大小, int 纵向大小)
        {
            Console.SetWindowSize(横向大小, 纵向大小);
        }
        private void 获取按键()
        {
            while (系统与设置.程序运行)
            {
                var 按键 = Console.ReadKey(true).Key;
                if (按键 == ConsoleKey.LeftArrow) { 菜单上一选项(); }
                if (按键 == ConsoleKey.RightArrow) { 菜单下一选项(); }
                if (按键 == ConsoleKey.Enter) { 确认选项(); }
                Thread.Sleep(系统与设置.界面刷新毫秒 - 1);

            }
        }

        private void 确认选项()
        {
            已选项路径.Add(当前选择项);
            var 当前战场 = 实体数据.数据组.战场数据;
            var 显示角色 = 当前战场.当前行动角色;
            var 待选选项 = 显示角色.注册战斗选项.选项列表;
            for (int i = 0; i < 已选项路径.Count; i++)
            {
                if (待选选项[已选项路径[i]].子选项组 == null)
                {
                    待选选项[已选项路径[i]].执行选项(显示角色, 当前战场, 待选选项[已选项路径[i]].储存类型);
                    return;
                }
                if (待选选项[已选项路径[i]].子选项组!.选项列表.Count != 0)
                {
                    待选选项[已选项路径[i]].刷新菜单(显示角色, 当前战场, 待选选项[已选项路径[i]].储存类型);
                    待选选项 = 待选选项[已选项路径[i]].子选项组!.选项列表;
                }
                else { 待选选项[已选项路径[i]].执行选项(显示角色, 当前战场, 待选选项[已选项路径[i]].储存类型); }

            }
            //选中第一个选项
            if (当前选项 != null && 当前选项.Count != 0) { 当前选择项 = 0; }

        }

        private void 启动界面刷新()
        {
            显示.光标设置(系统与设置.启用系统光标);
            Task 刷新界面 = new Task(() =>
            {

                while (系统与设置.程序运行)
                {
                    更新界面();
                    Thread.Sleep(系统与设置.界面刷新毫秒);
                }
            });
            刷新界面.Start();
        }
        private void 更新界面()
        {
            //更新系统信息
            var 启动时间 = 实体数据.数据组.战场数据.启动战斗时间;
            string 时间信息 = $"时间 {DateTime.Now.ToString("MM/dd HH:MM:ss")} 模拟战斗测试 已进行{Math.Round(DateTime.Now.Subtract(启动时间).TotalSeconds, 0)}秒";
            显示.输出(系统信息位置, 0, 时间信息);
            //更新回合行信息

            string 回合行信息 = $"第{实体数据.数据组.战场数据.回合数}回合";
            foreach (var 行动条 in 实体数据.数据组.战场数据.行动条)
            {
                回合行信息 += $" | ";
                foreach (var 角色 in 行动条)
                {
                    回合行信息 += $" [{角色.角色名称}] ";
                }
            }
            显示.转到行(回合行位置); 显示.清空本行();
            显示.输出(回合行位置, 0, 回合行信息);
            //更新决意行信息
            var 决意进度条 = 显示.新建进度条(30, '[', ']', ' ', '-', 实体数据.数据组.战场数据.决意值, 实体数据.数据组.战场数据.决意值上限, true);
            string 决意行信息 = $"决意 {实体数据.数据组.战场数据.决意值}/{实体数据.数据组.战场数据.决意值上限} {决意进度条.进度条}";
            显示.输出(决意行位置, 0, 决意行信息);
            //更新击破行信息
            var 击破进度条 = 显示.新建进度条(30, '[', ']', ' ', '-', 实体数据.数据组.战场数据.击破值, 实体数据.数据组.战场数据.击破值上限, true);
            string 击破行信息 = $"击破 {实体数据.数据组.战场数据.击破值}/{实体数据.数据组.战场数据.击破值上限} {决意进度条.进度条}";
            显示.输出(击破行位置, 0, 击破行信息);
            //更新队伍信息
            int 角色数 = 0;
            foreach (var 角色信息 in 实体数据.数据组.队伍数据[队伍类型.我方队伍].队伍成员)
            {
                int 当前横列位置 = 角色数 + 角色数 * 系统与设置.横向列表间距;
                string 角色名称显示 = ""; string 生命显示 = ""; string 符力显示 = ""; string 怒气显示 = "";
                角色名称显示 += $"{角色信息.角色名称}";
                var 生命条 = 显示.新建进度条(10, '[', ']', ' ', '-', 角色信息.生命值, 角色信息.生命值上限, false);
                var 生命数据 = $"{角色信息.生命值}/{角色信息.生命值上限}";
                生命显示 += $"HP: {生命条.进度条} {生命数据}";
                var 符力条 = 显示.新建进度条(10, '[', ']', ' ', '-', 角色信息.符力值, 角色信息.符力值上限, false);
                var 符力数据 = $"{角色信息.符力值}/{角色信息.符力值上限}";
                符力显示 += $"SC: {符力条.进度条} {符力数据}";
                var 怒气条 = 显示.新建进度条(10, '[', ']', ' ', '-', 角色信息.怒气值, 角色信息.怒气值上限, false);
                var 怒气数据 = $"{角色信息.怒气值}/{角色信息.怒气值上限}";
                怒气显示 += $"AP: {怒气条.进度条} {怒气数据}";
                显示.输出(主角状态起始行, 当前横列位置, 角色名称显示);
                显示.输出(主角状态起始行 + 1, 当前横列位置, 生命显示);
                显示.输出(主角状态起始行 + 2, 当前横列位置, 符力显示);
                显示.输出(主角状态起始行 + 3, 当前横列位置, 怒气显示);
                角色数++;
            }
            //更新敌队信息
            角色数 = 0;
            显示.转到行(敌方状态起始行); 显示.清空本行();
            显示.转到行(敌方状态起始行 + 1); 显示.清空本行();
            显示.转到行(敌方状态起始行 + 2); 显示.清空本行();
            显示.转到行(敌方状态起始行 + 3); 显示.清空本行();
            foreach (var 角色信息 in 实体数据.数据组.队伍数据[队伍类型.敌方队伍].队伍成员)
            {
                int 当前横列位置 = 角色数 + 角色数 * 系统与设置.横向列表间距;
                string 角色名称显示 = ""; string 生命显示 = ""; string 符力显示 = ""; string 怒气显示 = "";
                角色名称显示 += $"{角色信息.角色名称}";
                var 生命条 = 显示.新建进度条(10, '[', ']', ' ', '-', 角色信息.生命值, 角色信息.生命值上限, false);
                var 生命数据 = $"{角色信息.生命值}/{角色信息.生命值上限}";
                生命显示 += $"HP: {生命条.进度条} {生命数据}";
                var 符力条 = 显示.新建进度条(10, '[', ']', ' ', '-', 角色信息.符力值, 角色信息.符力值上限, false);
                var 符力数据 = $"{角色信息.符力值}/{角色信息.符力值上限}";
                符力显示 += $"SC: {符力条.进度条} {符力数据}";
                var 怒气条 = 显示.新建进度条(10, '[', ']', ' ', '-', 角色信息.怒气值, 角色信息.怒气值上限, false);
                var 怒气数据 = $"{角色信息.怒气值}/{角色信息.怒气值上限}";
                怒气显示 += $"AP: {怒气条.进度条} {怒气数据}";
                显示.输出(敌方状态起始行, 当前横列位置, 角色名称显示);
                显示.输出(敌方状态起始行 + 1, 当前横列位置, 生命显示);
                显示.输出(敌方状态起始行 + 2, 当前横列位置, 符力显示);
                显示.输出(敌方状态起始行 + 3, 当前横列位置, 怒气显示);
                角色数++;
            }
            //更新日志信息
            显示.转到行(日志起始行);
            显示.输出行($"战斗日志：");
            int 当前行数 = 1;
            for (int i = 实体数据.数据组.战场数据.日志.Count - 1; i > 0; i--)
            {
                if (当前行数 >= 10) { break; }
                显示.转到行(日志起始行 + 当前行数);
                显示.清空本行();
                显示.输出(日志起始行 + 当前行数, 0, 实体数据.数据组.战场数据.日志[i]);
                当前行数++;
            }
            //显示选项信息
            显示.转到行(操作菜单起始行);
            显示.输出行($" {实体数据.数据组.战场数据.当前行动角色.角色名称} 选项");

            int 当前项 = 0;
            显示玩家菜单(实体数据.数据组.战场数据.当前行动角色);
            for (int i = 0; i < 当前选项.Count; i++)
            {
                if (当前项 == 当前选择项)
                {
                    显示.更换控制台颜色(ConsoleColor.Green);
                    显示.继续输出($" [{当前选项[当前项]}] ");
                    显示.更换控制台颜色(ConsoleColor.White);
                }
                if (当前项 != 当前选择项)
                {
                    显示.更换控制台颜色(ConsoleColor.DarkGreen);
                    显示.继续输出($" [{当前选项[当前项]}] ");
                    显示.更换控制台颜色(ConsoleColor.White);
                }
                当前项++;
            }



        }
        public void 重置玩家菜单()
        {
            已选项路径.Clear();
            当前选择项 = 0;
        }
        public void 显示玩家菜单(角色 显示角色)
        {
            if (显示角色.角色状态 != 角色.状态.正常) { return; }
            var 待选选项 = 显示角色.注册战斗选项.选项列表;
            if (已选项路径.Count != 0)
            {
                for (int i = 0; i < 当前菜单路径.Count; i++) { if (已选项路径[i] == 当前菜单路径[i]) { return; } }
            }
            当前选项.Clear();
            for (int i = 0; i < 已选项路径.Count; i++)
            {

                if (待选选项[已选项路径[i]].子选项组 == null) { 显示.日志输出(显示.日志类型.中断, "无效的子选项组"); return; }
                待选选项 = 待选选项[已选项路径[i]].子选项组!.选项列表;
            }
            foreach (var 选项 in 待选选项)
            {
                当前选项.Add(选项.选项名称.ToString());
            }

            当前菜单路径.Clear();
            for (int i = 0; i < 已选项路径.Count; i++) { 当前菜单路径.Add(已选项路径[i]); }
        }

        public void 菜单上一选项()
        {
            if (当前选择项 <= 0) { 实体数据.数据组.战场数据.日志.Add("已经是第一个选项了"); return; }
            当前选择项 -= 1;
            实体数据.数据组.战场数据.日志.Add($"已选择{当前选择项}");
        }

        public void 菜单下一选项()
        {
            if (当前选择项 + 1 >= 当前选项.Count) { 实体数据.数据组.战场数据.日志.Add("已经是最后一个选项了"); return; }
            当前选择项 += 1;
            实体数据.数据组.战场数据.日志.Add($"已选择{当前选择项}");
        }

        public void 下一级菜单()
        {

        }

        internal void 战斗结束(战场属性 战场, 队伍类型 失败队伍, 队伍类型 胜利队伍)
        {
            系统与设置.程序运行 = false;
            var 启动时间 = 实体数据.数据组.战场数据.启动战斗时间;
            var 秒 = Math.Round(DateTime.Now.Subtract(启动时间).TotalSeconds, 0);
            显示.清空屏幕();
            if (胜利队伍 == 队伍类型.我方队伍)
            {
                var 敌队 = 战场.队伍数据![队伍类型.敌方队伍];
                显示.日志输出(显示.日志类型.信息, $"战斗在{秒}秒内结束，我方胜利，获得{敌队.物品列表.Count}个物品与{敌队.队伍金钱}金钱，每个成员增加{敌队.队伍经验值}经验{敌队.队伍经验值 / 战场.队伍数据[队伍类型.我方队伍].队伍成员[0].经验值上限 * 100}%");
                foreach (var 日志行 in 战场.日志)
                {
                    显示.输出行(日志行);
                }
            }
            if (胜利队伍 == 队伍类型.敌方队伍)
            {
                显示.日志输出(显示.日志类型.信息, $"战斗在{秒}秒内结束，战斗失败，我方全灭");
                foreach (var 日志行 in 战场.日志)
                {
                    显示.输出行(日志行);
                }
            }

        }
    }

    public class 界面与实体交互中间件 : 战斗流程
    {
        public 界面与实体交互中间件(数据组 数据组, string 文件路径) : base(数据组)
        {

        }

        public override void 触发玩家行动(角色 使用角色)
        {
            if (使用角色 == null) { return; }
            if (主界面.当前界面 == null) { 等待主界面(使用角色); return; }
            主界面.当前界面.重置玩家菜单();
            主界面.当前界面.显示玩家菜单(使用角色);

        }

        public override void UI战斗结束(战场属性 战场, 队伍类型 失败队伍, 队伍类型 胜利队伍)
        {
            主界面.当前界面!.战斗结束(战场, 失败队伍, 胜利队伍);
        }

        public void 等待主界面(角色 使用角色)
        {
            Thread 等待线程 = new Thread(() =>
            {
                bool 完成等待 = false;
                while (!完成等待)
                {
                    if (主界面.当前界面 != null)
                    {
                        主界面.当前界面.显示玩家菜单(使用角色);
                        完成等待 = true;
                    }

                }

            });
            等待线程.Start();

        }
    }
}
